<?php
///////////////////////////////////////////////////////////////////////////////////////////////////////
//  这个文件是 JCAT PHP框架的一部，该项目和此文件 均遵循 GNU 自由软件协议
// 
//  Copyleft 2008 JeCat.cn(http://team.JeCat.cn)
//
//
//  JCAT PHP框架 的正式全名是：Jellicle Cat PHP Framework。
//  “Jellicle Cat”出自 Andrew Lloyd Webber的音乐剧《猫》（《Prologue:Jellicle Songs for Jellicle Cats》）。
//  JCAT 是一个开源项目，它像音乐剧中的猫一样自由，你可以毫无顾忌地使用JCAT PHP框架。JCAT 由中国团队开发维护。
//  正在使用的这个版本是：0.5.0 / SVN信息: $Id: class.JCAT_UIObject.php 1603 2009-03-31 15:35:42Z alee $
//
//
//
//  相关的链接：
//    [主页] http://jcat.JeCat.cn
//    [下载(HTTP)] http://code.google.com/p/jcat-php/downloads/list
//    [下载(svn)] svn checkout http://jcat-php.googlecode.com/svn/branches/0.4.0/Framework/ JCAT0.4
//    [在线文档] http://jcat.JeCat.cn/document
//    [社区] http://jj.jecat.cn/forum-7-1.html
//  不很相关：
//    [MP3] http://www.google.com/search?q=jellicle+songs+for+jellicle+cats+Andrew+Lloyd+Webber
//    [VCD/DVD] http://www.google.com/search?q=CAT+Andrew+Lloyd+Webber+video
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
/*-- Project Introduce --*/
namespace JCAT ;




/**
 * UI 对象
 *
 * @author		alee
 * @access		public
 */
class UIObject
{

	/**
	 * 
	 * @access	public
	 * @param	$sSourceStream	string	在模版中的原文
	 * @return	void
	 */
	function UIObject( $sSourceStream )
	{	
		ASSERT::ASSERT_STRING($sSourceStream) ;
	
		$this->SetSource($sSourceStream) ;
		$this->SetCompiled($sSourceStream) ;

		// Global Id
		$this->nUIObjectGlobalId = self::$nUIObjectAssignedId ++ ;
		self::$arrGlobalInstances[$this->nUIObjectGlobalId] = $this ;
		
		$this->aCompilerQueue = new Queue() ;
	}
	
	/**
	 * 设置对象属性 nEndByteInLine
	 *
	 * @access	public
	 * @param	$nEndByteInLine		int	PropertyDescription
	 * @return	void
	 */
	public function SetEndByteInLine($nEndByteInLine)
	{
		$this->nEndByteInLine = $nEndByteInLine ;
	}
	
	/**
	 * 取得对象属性 nEndByteInLine
	 *
	 * @access	public
	 * @return	int
	 */
	public function GetEndByteInLine()
	{
		return $this->nEndByteInLine ;
	}
	
	/**
	 * 设置对象属性 nStartByteInLine
	 *
	 * @access	public
	 * @param	$nStartByteInLine		int	PropertyDescription
	 * @return	void
	 */
	public function SetStartByteInLine($nStartByteInLine)
	{
		$this->nStartByteInLine = $nStartByteInLine ;
	}
	
	/**
	 * 取得对象属性 nStartByteInLine
	 *
	 * @access	public
	 * @return	int
	 */
	public function GetStartByteInLine()
	{
		return $this->nStartByteInLine ;
	}
	
	/**
	 * 设置对象属性 nEndByte
	 *
	 * @access	public
	 * @param	$nEndByte		int	PropertyDescription
	 * @return	void
	 */
	public function SetEndByte($nEndByte)
	{
		$this->nEndByte = $nEndByte ;
	}
	
	/**
	 * 取得对象属性 nEndByte
	 *
	 * @access	public
	 * @return	int
	 */
	public function GetEndByte()
	{
		return $this->nEndByte ;
	}
	
	/**
	 * 设置对象属性 nStartByte
	 *
	 * @access	public
	 * @param	$nStartByte		int	PropertyDescription
	 * @return	void
	 */
	public function SetStartByte($nStartByte)
	{
		$this->nStartByte = $nStartByte ;
	}
	
	/**
	 * 取得对象属性 nStartByte
	 *
	 * @access	public
	 * @return	int
	 */
	public function GetStartByte()
	{
		return $this->nStartByte ;
	}
	
	/**
	 * 设置对象属性 nEndLine
	 *
	 * @access	public
	 * @param	$nEndLine		int	PropertyDescription
	 * @return	void
	 */
	public function SetEndLine($nEndLine)
	{
		$this->nEndLine = $nEndLine ;
	}
	
	/**
	 * 取得对象属性 nEndLine
	 *
	 * @access	public
	 * @return	int
	 */
	public function GetEndLine()
	{
		return $this->nEndLine ;
	}
	
	/**
	 * 设置对象属性 nStartLine
	 *
	 * @access	public
	 * @param	$nStartLine		int	PropertyDescription
	 * @return	void
	 */
	public function SetStartLine($nStartLine)
	{
		$this->nStartLine = $nStartLine ;
	}
	
	/**
	 * 取得对象属性 PropertyDescription
	 *
	 * @access	public
	 * @return	int
	 */
	public function GetStartLine()
	{
		return $this->nStartLine ;
	}
	
	/**
	 * 设置对象属性 TemplateFile
	 *
	 * @access	public
	 * @param	$sTemplateFile		string	TemplateFile
	 * @return	void
	 */
	public function SetTemplateFile($sTemplateFile)
	{
		$this->sTemplateFile = $sTemplateFile ;
	}
	
	/**
	 * 取得对象属性 TemplateFile
	 *
	 * @access	public
	 * @return	string
	 */
	public function GetTemplateFile()
	{
		return $this->sTemplateFile ;
	}
	
	/**
	 * return a global id of all ui object
	 *
	 * @access	public
	 * @return	int
	 */
	public function GetGlobalId()
	{
		return $this->nUIObjectGlobalId ;
	}
	
	/**
	 * return a Instance by it's global id
	 *
	 * @access	public
	 * @param	$nGlobalId
	 * @static
	 * @return	UIObject
	 */
	static public function GetGlobalInstance($nGlobalId)
	{
		return isset(self::$arrGlobalInstances[$nGlobalId]) ?
							self::$arrGlobalInstances[$nGlobalId] :
							null ;
	}
	
	/**
	 * 设置所在模版
	 * 
	 * @access	public
	 * @param	$aTempate	UI	What's this Parameter ?
	 * @return	old_var
	 */
	public function SetTemplate( UI $aTempate ) 
	{
		$old_var = $this->aTemplate ;
		$this->aTemplate = $aTempate ;
		return $old_var ;
	}



	/**
	 * 取得所在模版
	 * 
	 * @access	public
	 * @return	UI
	 */
	public function GetTemplate() 
	{
		return $this->aTemplate ;
	}	

	/**
	 * 设置 分析器
	 * 
	 * @access	public
	 * @param	$aParser	IUIObjectParser	分析器
	 * @return	old_var
	 */
	public function SetParser( IUIObjectParser $aParser ) 
	{
		$old_var = $this->aParser ;
		$this->aParser = $aParser ;
		return $old_var ;
	}



	/**
	 * 取回 分析器
	 * 
	 * @access	public
	 * @return	IUIObjectParser
	 */
	public function GetParser(  ) 
	{
		return $this->aParser ;
	}



	/**
	 * 设置 编译此模版的编译器，可以是null
	 * 
	 * @access	public
	 * @param	$Compiler	IUIObjectCompiler		编译器
	 * @return	void
	 */
	public function PutInCompiler( $Compiler ) 
	{
		ASSERT::ASSERT_ISTHESE($Compiler,array('JCAT\IUIObjectCompiler')) ;

		// 输入类名
		if( is_string($Compiler) )
		{
			$aCompiler = Singleton::GetGlobalInstance($Compiler) ;
		}
		else
		{
			$aCompiler = $Compiler ;
		}

		$this->aCompilerQueue->In($aCompiler) ;
	}


	

	/**
	 * 取得 编译器
	 * 
	 * @access	public
	 * @return	IUIObjectCompiler
	 */
	public function TakeOutCompiler() 
	{
		return $this->aCompilerQueue->Out() ;
	}

	
	

	/**
	 * 取得原文
	 * 
	 * @access	public
	 * @return	string
	 */
	public function GetSource(  ) 
	{
		return $this->sSourceStream ;
	}

	/**
	 * 设置原文
	 * 
	 * @access	public
	 * @return	old_value
	 */
	protected function SetSource( $sSource ) 
	{
		ASSERT::ASSERT_STRING($sSource) ;
		
		$old_value = $this->sSourceStream ;
		$this->sSourceStream = $sSource ;
		return $old_value ;
	}



	/**
	 * 取得编译后的内容
	 * 
	 * @access	public
	 * @return	string
	 */
	public function GetCompiled() 
	{
		return $this->sCompiledStream ;
	}



	/**
	 * 设置 编译后的内容
	 * 
	 * @access	public
	 * @param	$sStream	string	What's this Parameter ?
	 * @return	old_value
	 */
	public function SetCompiled( $sStream ) 
	{
		ASSERT::ASSERT_STRING($sStream) ;
		
		$old_var = $this->sCompiledStream ;
		$this->sCompiledStream = $sStream ;
		return $old_var ;
	}
	
	
	/**
	 * 比较UI对象的位置
	 *
	 * @access	public
	 * @param	$aUIObject	UIObject	用于比较的另外一个对象
	 * @return	self::LOCAL_IN, self::LOCAL_OUT, self::LOCAL_FRONT, self::LOCAL_BEHIND
	 */
	public function CompareLocal(UIObject $aUIObject)
	{
		// 前
		if( $aUIObject->GetEndByte() <= $this->GetStartByte() )
			return self::LOCAL_FRONT ;
			
		// 后
		if( $aUIObject->GetStartByte() >= $this->GetEndByte() )
			return self::LOCAL_BEHIND ;
		
		
		// 内
		if( $aUIObject->GetStartByte() >= $this->GetStartByte() )
			return self::LOCAL_IN ;
			
		// 外
		if( $aUIObject->GetStartByte() <= $this->GetStartByte() )
			return self::LOCAL_OUT ;
		
		// 不支持
		throw new $this->CreateException(Language::SentenceEx('不支持交叉UI对象。','JCAT',null), Exception::MakeExceptionCode(__CLASS__,2)) ;
	}
	
	/**
	 * 插入一个 UIObject 
	 *
	 * @access	public
	 * @param	$UIObject	UIObject	UI对象
	 * @return	void
	 */
	public function AddUIObject( UIObject $aInUIObject )
	{
		$arrNewList = array() ;
		$aUIObject = $aInUIObject ;

		foreach($this->arrChildUIObject as $aMyUIObject)
		{
			ASSERT::ASSERT_INSTANCE($aMyUIObject,'JCAT\UIObject') ;
			
			
			if($aUIObject)
			{
				$nLocal = $aMyUIObject->CompareLocal($aUIObject) ;
				
				switch( $nLocal )
				{
					case self::LOCAL_FRONT :
						$arrNewList[] = $aUIObject ;				// 插入到当前位置
						$arrNewList[] = $aMyUIObject ;
						$aUIObject = null ;
						break ;
						
					case self::LOCAL_BEHIND :
						$arrNewList[] = $aMyUIObject ;
						break ;
						
					case self::LOCAL_IN :
						$aMyUIObject->AddUIObject($aUIObject) ;
						$arrNewList[] = $aMyUIObject ;
						$aUIObject = null ;
						break ;
						
					case self::LOCAL_OUT :

						$aUIObject->AddUIObject($aMyUIObject) ;
						//$arrNewList[] = $aUIObject ;
						//$aUIObject = null ;
						break ;
				}
			}
			else
				$arrNewList[] = $aMyUIObject ;
		}
		
		// 加入到最后
		if( $aUIObject )
			$arrNewList[] = $aUIObject ;

		// 设置新的清单
		$this->arrChildUIObject = $arrNewList ;
	}
	
	
	/**
	 * 
	 *
	 * @access	public
	 * @param	$nIdx	int		What's this Parameter ?
	 * @return	UIObject, null
	 */
	public function RemvoeUIObject($nIdx)
	{
		ASSERT::ASSERT_INT($nIdx) ;
		
		if( isset($this->arrChildUIObject[$nIdx]) )
		{
			$aRet = $this->arrChildUIObject[$nIdx] ;
			unset($this->arrChildUIObject[$nIdx]) ;
			return $aRet ;
		}
		
	}
	
	/**
	 * 
	 *
	 * @access	public
	 * @param	$nIdx	int		What's this Parameter ?
	 * @return	UIObject, null
	 */
	public function GetUIObject($nIdx)
	{
		return isset($this->arrChildUIObject[$nIdx])? $this->arrChildUIObject[$nIdx]: null ;
	}
	
	
	/**
	 * 创建一个 UIObject 的迭代器
	 *
	 * @access	public
	 * @return	ArrayIterator
	 */
	public function CreateUIObjectIterator()
	{
				return new ArrayIterator($this->arrChildUIObject) ;
	}
	


	/**
	 * 定位
	 *
	 * @access	public
	 * @param	$sTemplateStream	string		模版原文
	 * @param	$nStart				int			开始位置
	 * @return	void
	 */
	public function Locate( $sTemplateStream, $nStart )
	{
		ASSERT::ASSERT_STRING($sTemplateStream) ;
		ASSERT::ASSERT_INT($nStart) ;
		
		$sSourceStream = $this->GetSource() ;
		
		// 空对象
		if( empty($sSourceStream) )
		{
			$this->SetStartByte( -1 ) ;
			$this->SetEndByte( -1 ) ;
			$this->SetStartLine( -1 ) ;
			$this->SetEndLine( -1 ) ;
			$this->SetEndLine( -1 ) ;
			$this->SetStartByteInLine( -1 ) ;
			$this->SetEndByteInLine( -1 ) ;
		
			return ;
		}
		
		$nTotalByte = strlen($sTemplateStream) ;
		
		// 起止字节位置
		$nStartByte = strpos($sTemplateStream,$sSourceStream,$nStart) ;
		$nEndByte = $nStartByte + strlen($sSourceStream) - 1 ;
		
		$this->SetStartByte( $nStartByte ) ;
		$this->SetEndByte( $nEndByte ) ;
	
	
		// 起止行数
		$nStartLine = ($nStartByte<=0)? 0: substr_count($sTemplateStream,"\n",0,$nStartByte) ;
		$nEndLine =($nEndByte<=0)? 0: substr_count($sTemplateStream,"\n",0,$nEndByte) ;
		
		$this->SetStartLine( $nStartLine ) ;
		$this->SetEndLine( $nEndLine ) ;
		
		
		// 在行上的起止位置
		$nLineHeadOfStart = strrpos( substr($sTemplateStream,0,$nStartByte),"\n" ) + 1;			// 起始点 所在行 的行首位置
		$nLineHeadOfEnd = strrpos( substr($sTemplateStream,0,$nEndByte),"\n" ) + 1;				// 结束点 所在行 的行首位置
		
		$nStartInLine = $nStartByte - $nLineHeadOfStart ;
		$nEndInLine = $nEndByte - $nLineHeadOfEnd ;
		
		$this->SetStartByteInLine($nStartInLine) ;
		$this->SetEndByteInLine($nEndInLine) ;
		
		
	}
	

	/**
	 * 编译
	 * 
	 * @access	public
	 * @return	void
	 */
	public function Compile() 
	{
		// 编译自己
		while( $aCompiler=$this->TakeOutCompiler()  )
		{
			$aCompiler->Compile($this) ;
		}
	}
	
	
	
	public function _PrintUIObjectsForDebug()
	{
		//print_r($this->arrChildUIObject) ;
	
		$aIterator = $this->CreateUIObjectIterator() ;
		$aIterator->First() ;
		while( !$aIterator->IsDone() )
		{
			$aUIObject = $aIterator->Current() ;// print_r($aUIObject) ;
			
			if( GlobalFunc::IsThese($aUIObject,array('UIHtmlNode')) )
			{
				echo $aUIObject->GetNodeName() . "\r\n" ;
			}
			
			$aIterator->Next() ;
		}
	}

	// 属性 ///////////////////////////////////////////////////////////////////////////////

	static private $nUIObjectAssignedId = 0 ;
	
	static private $arrGlobalInstances = array() ;
	
	/**
	 * Description
	 * 
	 * @access	private
	 * @var		int
	 */
	private $nUIObjectGlobalId = -1 ;
	
	
	/**
	 * 所在模版
	 * 
	 * @access	private
	 * @var		UI
	 */
	private $aTemplate ;

	/**
	 * What's this Attribute ?
	 * 
	 * @access	private
	 * @var		IUIObjectParser
	 */
	private $aParser ;
	
	/**
	 * Description
	 * 
	 * @access	private
	 * @var		Queue
	 */
	private $aCompilerQueue ;

	/**
	 * What's this Attribute ?
	 * 
	 * @access	private
	 * @var		string
	 */
	private $sSourceStream ;

	/**
	 * What's this Attribute ?
	 * 
	 * @access	private
	 * @var		string
	 */
	private $sCompiledStream ;


	/**
	 * 下级UI对象
	 * 
	 * @access	private
	 * @var		string
	 */
	protected $arrChildUIObject = array() ;
	
	

	/**
	 * 取得对象位置的描述
	 *
	 * @access	public
	 * @return	string
	 */
	public function GetLocationDescription()
	{
		return Language::SentenceEx('行: %s; 列: %s; 文件: %s','JCAT',null
					, $this->GetStartLine()
					, $this->GetStartByteInLine()
					, $this->GetTemplateFile() ) ;
	}
	
	
	/**
	 * create a Exception
	 *
	 * @access	public
	 * @param	$sMsg=''		string		异常消息
	 * @param	$nCode=0		int		JCAT异常ID
	 * @return	Exception
	 */
	public function CreateException($sMsg='',$nCode=0)
	{
		return new Exception($sMsg,$nCode) ;
	}

	// 位置信息 －－－－－－－－－－－－－－－
	
	/**
	 * 所在模版文件
	 * 
	 * @access	private
	 * @var		string
	 */
	private $sTemplateFile = '' ;
	
	/**
	 * 开始行
	 * 
	 * @access	private
	 * @var		int
	 */
	private $nStartLine = 0 ;

	/**
	 * 结束行
	 * 
	 * @access	private
	 * @var		int
	 */
	private $nEndLine = 0 ;

	/**
	 * 开始字节数
	 * 
	 * @access	private
	 * @var		int
	 */
	private $nStartByte = 0 ;

	/**
	 * 结束字节数
	 * 
	 * @access	private
	 * @var		int
	 */
	private $nEndByte = 0 ;

	/**
	 * 在开始行中的字节位置
	 * 
	 * @access	private
	 * @var		int
	 */
	private $nStartByteInLine = 0 ;

	/**
	 * 在结束行中的字节位置
	 * 
	 * @access	private
	 * @var		int
	 */
	private $nEndByteInLine = 0 ;


	
	protected $arrGet = array() ;
	protected $arrSet = array() ;


	const LOCAL_MIN = 1 ;
	/**
	 * 位置内
	 * 
	 * @access	const
	 * @var		int
	 */
	const LOCAL_IN = 1 ;
	/**
	 * 位置外
	 * 
	 * @access	const
	 * @var		int
	 */
	const LOCAL_OUT = 2 ;
	/**
	 * 位置前
	 * 
	 * @access	const
	 * @var		int
	 */
	const LOCAL_FRONT = 3 ;
	/**
	 * 位置后
	 * 
	 * @access	const
	 * @var		int
	 */
	const LOCAL_BEHIND = 4 ;
	
	const LOCAL_MAX = 1 ;
	
	
}


/*macro_exception_code:2*/
?>